package model;

import java.util.ArrayList;

import org.workplicity.util.Helper;
import org.workplicity.worklet.WorkletContext;

import com.mongodb.BasicDBObject;
import com.mongodb.util.JSON;

import cc.test.bridge.LineInterface;
import cc.test.bridge.SublineInterface;
import cc.test.bridge.TransactionInterface;

public class Subline extends Line implements SublineInterface
{
	private static final long serialVersionUID = 1L;
	protected ArrayList<Integer> transactionIds = new ArrayList<Integer>();
	protected Integer parentLineId = -1;
	protected String repositoryName = "Sublines";
	protected Integer subNumber = null;

	/**
	 * Default no argument constructor
	 */
	public Subline()
	{
	}

	/**
	 * Subline constructor taking a parentLineId
	 * 
	 * @param parentLineId The Integer containing the parentLineId
	 */
	public Subline(Integer parentLineId)
	{
		this.parentLineId = parentLineId;
	}

	/**
	 * Getter for transactionIds
	 * 
	 * @return An ArrayList<Integer> of transcationIds
	 */
	public ArrayList<Integer> getTransactionIds()
	{
		return transactionIds;
	}

	/**
	 * Setter for transactionIds
	 * 
	 * @param transactionIds The ArrayList<Integer> of transactionIds
	 */
	public void setTransactionIds(ArrayList<Integer> transactionIds)
	{
		this.transactionIds = transactionIds;
	}

	/**
	 * Getter for parentLineId
	 * 
	 * @return An Integer containing the parentLineId
	 */
	public Integer getParentLineId()
	{
		return parentLineId;
	}

	/**
	 * Setter for parentLineId
	 * 
	 * @param parentLineId The Integer containing parentLineId
	 */
	public void setParentLineId(Integer parentLineId)
	{
		this.parentLineId = parentLineId;
	}

	/**
	 * Getter for repositoryName
	 * 
	 * @return An String containing the repositoryName
	 */
	public String getRepositoryName()
	{
		return repositoryName;
	}

	/**
	 * Setter for repositoryName
	 * 
	 * @param repositoryName The String containing repositoryName
	 */
	public void setRepositoryName(String repositoryName)
	{
		this.repositoryName = repositoryName;
	}
	
	@Override
	/**
	 * Getter for subNumber
	 * 
	 * @return An Integer containing the subNumber
	 */
	public Integer getSubNumber()
	{
		return this.subNumber;
	}

	/**
	 * Setter for setSubNumber
	 * 
	 * @param number The Integer containing setSubNumber
	 */
	public void setSubNumber(Integer number)
	{
		this.subNumber = number;
		// If created already (it is not in the create hamper)
		if (this.id != -1)
		{
			// If LineUpdates hamper does not contain the line already
			if (!Hampers.getSublineUpdates().containsKey(this.id))
			{
				Hampers.getSublineUpdates().put(this.id, this);
			}
		}
	}

	/**
	 * Setter for name
	 * 
	 * @param name The String containing name
	 */
	public void setName(String name)
	{
		this.name = name;
		// If created already (it is not in the create hamper)
		if (this.id != -1)
		{
			// If SublineUpdates hamper does not contain the subline already
			if (!Hampers.getSublineUpdates().containsKey(this.id))
			{
				Hampers.getSublineUpdates().put(this.id, this);
			}
		}
	}

	/**
	 * Getter for serialVersionUID
	 * 
	 * @return An long containing the serialVersionUID
	 */
	public static long getSerialversionuid()
	{
		return serialVersionUID;
	}

	@Override
	/**
	 * Adds a Transaction to the subline
	 * 
	 * @param transaction The TransactionInterface to add to a subline
	 */
	public void add(TransactionInterface transaction)
	{
		if (this.id == -1)
		{
			Integer uid = (int) System.currentTimeMillis();
			((Transaction) transaction).setParentLineId(uid);
			
			Hampers.getSublineUpdates().put(uid, this);
			Hampers.getTransCreates().put(-1, transaction);
		}
		else
		{
			Hampers.getSublineUpdates().put(this.id, this);
			Hampers.getTransCreates().put(-1, transaction);
		}

	}

	@Override
	/**
	 * Creates a new Transaction
	 * 
	 * @return A new Transaction whose parentLineId is this subline's id
	 */
	public TransactionInterface createTransaction()
	{
		return new Transaction(this.id);
	}

	@Override
	/**
	 * Deletes a transaction from the subline
	 * 
	 * @param trans The TransactionInterface to delete
	 */
	public void delete(TransactionInterface trans)
	{
		if (this.id == -1)
		{
			Integer uid = (int) System.currentTimeMillis();
			((Transaction) trans).setParentLineId(uid);
			
			Hampers.getSublineUpdates().put(uid, this);
			Hampers.getTransDeletes().put(-1, trans);
		}
		else
		{
			Hampers.getSublineUpdates().put(this.id, this);
			Hampers.getTransDeletes().put(-1, trans);
		}

	}

	@SuppressWarnings("unchecked")
	@Override
	/**
	 * Fetches the Transcations that belong to the subline
	 * 
	 * @return An ArrayList<TransactionInterface> containing the TransactionInterfaces
	 *         that were fetched.
	 */
	public ArrayList<TransactionInterface> fetchTransactions()
	{
		ArrayList<TransactionInterface> transactions = new ArrayList<TransactionInterface>();
		
		for (Integer i : this.getTransactionIds())
		{
			BasicDBObject predicate = new BasicDBObject();

			predicate.put("entry.id", i);
			String criteria = JSON.serialize(predicate);
			
			try
			{
				ArrayList<TransactionInterface> transaction = Helper.query(
						"Transactions", criteria, WorkletContext.getInstance());
				
				for (TransactionInterface trans : transaction)
				{
					transactions.add(trans);
				}
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}
		
		return transactions;
	}

	/**
	 * Commits a newly created Sublines to the repository
	 * 
	 * @return A boolean of if the Subline was successfully committed.
	 */
	public static Boolean commitSublineCreates()
	{
		Boolean successful = true;
		
		for (SublineInterface subline : Hampers.getSublineCreates().values())
		{
			// insert subline into Mongo
			try
			{
				successful = Helper.insert((Subline) subline, "Sublines",
						WorkletContext.getInstance());
				
				System.out
						.println("Created subline with id " + subline.getId());
			}
			catch (Exception e)
			{
				System.out.println("Error: Could not create subline with id "
						+ subline.getId());
				
				e.printStackTrace();
				successful = false;
			}
			
			// Give new Id to all linked transactions (if any)
			if (((Subline) subline).getTransactionIds().size() > 0)
			{
				for (Integer i : ((Subline) subline).getTransactionIds())
				{
					if (Hampers.getTransUpdates().containsKey(i))
					{
						((Transaction) Hampers.getTransUpdates().get(i))
								.setParentLineId(subline.getId());
					}
				}
			}
			
			// Give new Id to parent line
			if (Hampers.getLineUpdates().containsKey(
					((Subline) subline).getParentLineId()))
			{
				LineInterface line = Hampers.getLineUpdates().get(
						((Subline) subline).getParentLineId());
				
				if (!((Line) line).getSublineIds().contains(subline.getId()))
				{
					((Line) line).sublineIds.add(subline.getId());
				}
			}
			else if (Hampers.getLineCreates().containsKey(
					((Subline) subline).getParentLineId()))
			{
				LineInterface line = Hampers.getLineCreates().get(
						((Subline) subline).getParentLineId());
				
				if (!((Line) line).getSublineIds().contains(subline.getId()))
				{
					((Line) line).sublineIds.add(subline.getId());
				}
			}
		}
		
		return successful;
	}

	/**
	 * Commits an updated Subline to the repository
	 * 
	 * @return A boolean of if the Subline was successfully committed.
	 */
	public static Boolean commitSublineUpdates()
	{
		Boolean successful = true;
		
		for (SublineInterface subline : Hampers.getSublineUpdates().values())
		{
			// update subline in Mongo
			try
			{
				successful = Helper.insert((Subline) subline, "Sublines",
						WorkletContext.getInstance());
				
				System.out
						.println("Updated subline with id " + subline.getId());
			}
			catch (Exception e)
			{
				System.out.println("Error: Could not update subline with id "
						+ subline.getId());
				
				e.printStackTrace();
				successful = false;
			}
		}
		
		return successful;
	}

	/**
	 * Deletes a Subline from the repository, as well as all associated Transactions
	 * 
	 * @return A boolean of if the Subline was successfully deleted.
	 */
	public static Boolean commitSublineDeletes(Subline subline)
	{
		System.out.println("Deleting subline");
		
		// Delete all transactions associated
		Boolean successful = true;
		
		ArrayList<TransactionInterface> transactions = subline
				.fetchTransactions();
		
		for (TransactionInterface trans : transactions)
		{
			successful = successful && Transaction
					.commitTransactionDeletes((Transaction) trans);
		}
		
		if (successful)
		{
			try
			{
				successful = Helper.delete((Subline) subline, "Sublines",
						WorkletContext.getInstance());
				
				System.out
						.println("Deleted subline with id " + subline.getId());
			}
			catch (Exception e)
			{
				System.out.println("Error: Could not delete subline with id "
						+ subline.getId());
				
				e.printStackTrace();
				successful = false;
			}
			
			if (successful)
			{
				if (Hampers.getLineUpdates().containsKey(
						subline.getParentLineId()))
				{
					LineInterface line = Hampers.getLineUpdates().get(
							subline.getParentLineId());
					
					((Line) line).getSublineIds().remove(subline.id);
				}
				else if (Hampers.getLineCreates().containsKey(
						subline.getParentLineId()))
				{
					LineInterface line = Hampers.getLineCreates().get(
							subline.getParentLineId());
					
					((Line) line).getSublineIds().remove(subline.id);
				}
			}
		}
		else
		{
			System.out.println("Failed to delete all transactions");
		}

		return successful;
	}

	@Override
	/**
	 * Dummy commit function for SublineInterface 
	 */
	public Boolean commit()
	{
		return null;
	}
}
